| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="UTF-8"> |
| |
| <title>Location objects' custom [[GetPrototypeOf]] trap permit [[Prototype]] chain cycles to be created through them</title> |
| |
| <link rel="author" title="Jeff Walden" href="http://whereswalden.com/" /> |
| <link rel="help" href="https://tc39.github.io/ecma262/#sec-ordinarysetprototypeof" /> |
| <link rel="help" href="https://html.spec.whatwg.org/multipage/browsers.html#location-getprototypeof" /> |
| |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| </head> |
| <body> |
| <div id="log"></div> |
| |
| <hr /> |
| |
| <iframe id="same-origin-different-window"></iframe> |
| <iframe id="cross-origin-joined-via-document-domain"></iframe> |
| |
| <script> |
| "use strict"; |
| |
| // Handle same-origin, same-window testing first, before any async-requiring |
| // testing. |
| test(function() { |
| var LocationPrototype = Location.prototype; |
| var ObjectPrototype = Object.prototype; |
| |
| var loc = window.location; |
| |
| var locProto = Object.getPrototypeOf(loc); |
| assert_equals(locProto, LocationPrototype, |
| "loc's initial [[Prototype]]"); |
| |
| var originalLocProtoProto = Object.getPrototypeOf(locProto); |
| assert_equals(originalLocProtoProto, ObjectPrototype, |
| "Location.prototype's initial [[Prototype]]"); |
| |
| Object.setPrototypeOf(locProto, loc); |
| |
| assert_equals(Object.getPrototypeOf(locProto), loc, |
| "LocationPrototype's new [[Prototype]]"); |
| assert_equals(Object.getPrototypeOf(loc), locProto, |
| "loc's new [[Prototype]]"); |
| |
| // Reset so as not to muck with testharness.js expectations. |
| Object.setPrototypeOf(locProto, originalLocProtoProto); |
| }, "same-origin, same-window location cycle"); |
| |
| var pathdir = |
| location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1); |
| |
| var triggerCrossOriginTest = (function() { |
| var crossOrigin = |
| document.getElementById("cross-origin-joined-via-document-domain"); |
| |
| var t = async_test("cross-origin location has null prototype"); |
| |
| return new Promise(function(resolve, reject) { |
| crossOrigin.onload = t.step_func_done(function(e) { |
| try { |
| var win = crossOrigin.contentWindow; |
| |
| var loc = win.location; |
| |
| // Between un-opted-in windows, location objects appear to have null |
| // [[Prototype]]. |
| assert_equals(Object.getPrototypeOf(loc), null, |
| "cross-origin unjoined location's [[Prototype]"); |
| |
| resolve(); |
| } catch (e) { |
| reject(e); |
| throw e; |
| } |
| }); |
| |
| crossOrigin.src = |
| "//{{domains[www]}}:" + location.port + pathdir + "cross_origin_joined_frame.sub.html"; |
| }) |
| .catch(t.unreached_func("crossOrigin onload/src setting")); |
| })(); |
| |
| var triggerSameOriginTest = (function() { |
| var sameOriginDifferentWindow = |
| document.getElementById("same-origin-different-window"); |
| |
| var t = async_test("same-origin, different-window location cycle"); |
| |
| return new Promise(function(resolve, reject) { |
| sameOriginDifferentWindow.onload = t.step_func_done(function() { |
| try { |
| var win = sameOriginDifferentWindow.contentWindow; |
| |
| var loc = win.location; |
| var LocationPrototype = win.Location.prototype; |
| var ObjectPrototype = win.Object.prototype; |
| |
| var locProto = Object.getPrototypeOf(loc); |
| assert_equals(locProto, LocationPrototype, |
| "loc's initial [[Prototype]]"); |
| |
| var originalLocProtoProto = Object.getPrototypeOf(locProto); |
| assert_equals(originalLocProtoProto, ObjectPrototype, |
| "Location.prototype's initial [[Prototype]]"); |
| |
| Object.setPrototypeOf(locProto, loc); |
| |
| assert_equals(Object.getPrototypeOf(locProto), loc, |
| "LocationPrototype's new [[Prototype]]"); |
| assert_equals(Object.getPrototypeOf(loc), locProto, |
| "loc's new [[Prototype]]"); |
| |
| // Reset so as not to muck with testharness.js expectations. |
| Object.setPrototypeOf(locProto, originalLocProtoProto); |
| |
| resolve(); |
| } catch (e) { |
| reject(e); |
| throw e; |
| } |
| }); |
| |
| sameOriginDifferentWindow.src = "same_origin_frame.html"; |
| }) |
| .catch(t.unreached_func("sameOriginDifferentWindow onload/src setting")); |
| })(); |
| |
| function crossOriginJoinTest() { |
| var win = |
| document.getElementById("cross-origin-joined-via-document-domain") |
| .contentWindow; |
| |
| assert_equals(document.domain, "{{host}}"); |
| |
| var loc = win.location; |
| |
| var threw = false; |
| try { |
| // Still cross-origin until the document.domain set below. |
| win.Location; |
| } catch (e) { |
| threw = true; |
| } |
| |
| assert_equals(threw, true, |
| "accessing win.Location before joining win's origin"); |
| |
| // Join with other frames that have set |document.domain| to this same |
| // value -- namely, this cross-origin frame. Now access between the two |
| // windows should be permitted. |
| assert_equals(document.domain, "{{host}}", |
| "initial document.domain sanity check"); |
| document.domain = "{{host}}"; |
| |
| var LocationPrototype = win.Location.prototype; |
| var ObjectPrototype = win.Object.prototype; |
| |
| var locProto = Object.getPrototypeOf(loc); |
| assert_equals(locProto, LocationPrototype, |
| "loc's initial [[Prototype]]"); |
| |
| var originalLocProtoProto = Object.getPrototypeOf(locProto); |
| assert_equals(originalLocProtoProto, ObjectPrototype, |
| "Location.prototype's initial [[Prototype]]"); |
| |
| Object.setPrototypeOf(locProto, loc); |
| |
| assert_equals(Object.getPrototypeOf(locProto), loc, |
| "LocationPrototype's new [[Prototype]]"); |
| assert_equals(Object.getPrototypeOf(loc), locProto, |
| "loc's new [[Prototype]]"); |
| |
| // Reset so as not to muck with testharness.js expectations. |
| Object.setPrototypeOf(locProto, originalLocProtoProto); |
| } |
| |
| function run() { |
| var t = |
| async_test("cross-origin, but joined via document.domain, location cycle"); |
| |
| // The cross-origin/joined case must be tested after both unjoined same-origin |
| // and unjoined cross-origin tests: by mucking with document.domain, the |
| // cross-origin/joined case makes it impossible to perform those tests. |
| t.step(function() { |
| Promise.all([triggerCrossOriginTest, triggerSameOriginTest]) |
| .then(t.step_func_done(crossOriginJoinTest), |
| t.unreached_func("cross-origin joined error case")); |
| }); |
| } |
| run(); |
| </script> |
| </body> |
| </html> |