Implement the "noopener" feature for window.open()
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Mar 2017 16:15:16 +0000 (16:15 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Mar 2017 16:15:16 +0000 (16:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=163960
<rdar://problem/28941679>

Reviewed by Sam Weinig.

LayoutTests/imported/w3c:

Import test coverage from WPT upstream.

* resources/import-expectations.json:
* web-platform-tests/common/PrefixedLocalStorage.js: Added.
(PrefixedLocalStorage):
(PrefixedLocalStorage.prototype.clear):
(PrefixedLocalStorage.prototype.url):
(PrefixedLocalStorage.prototype.prefixedKey):
(PrefixedLocalStorage.prototype.setItem):
(PrefixedLocalStorage.prototype.onSet):
(PrefixedLocalStorageTest):
(PrefixedLocalStorageTest.prototype.cleanup):
(PrefixedLocalStorageResource):
* web-platform-tests/common/w3c-import.log:
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed-expected.txt: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed.html: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-expected.txt: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple-expected.txt: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple.html: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener-expected.txt: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener.html: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer-expected.txt: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer.html: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener.html: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/close-opener.html: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/message-window-opener.html: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/multiple-opener.html: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/no-opener.html: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/open-closer.html: Added.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/w3c-import.log: Copied from LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/w3c-import.log.
* web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/w3c-import.log:

Source/WebCore:

Implement the "noopener" feature for window.open(). If 'noopener' is passed to window.open()
then the new Window's opener property will be null.

Tests: imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed.html
       imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple.html
       imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener.html
       imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer.html
       imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener.html

* page/DOMWindow.cpp:
(WebCore::DOMWindow::createWindow):
* page/WindowFeatures.cpp:
(WebCore::parseWindowFeatures):
(WebCore::setWindowFeature):
* page/WindowFeatures.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@214251 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/resources/import-expectations.json
LayoutTests/imported/w3c/web-platform-tests/common/PrefixedLocalStorage.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/common/w3c-import.log
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/close-opener.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/message-window-opener.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/multiple-opener.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/no-opener.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/open-closer.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/w3c-import.log [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/w3c-import.log
Source/WebCore/ChangeLog
Source/WebCore/page/DOMWindow.cpp
Source/WebCore/page/WindowFeatures.cpp
Source/WebCore/page/WindowFeatures.h

index ee3d6db..db35e5c 100644 (file)
@@ -1,3 +1,43 @@
+2017-03-22  Chris Dumez  <cdumez@apple.com>
+
+        Implement the "noopener" feature for window.open()
+        https://bugs.webkit.org/show_bug.cgi?id=163960
+        <rdar://problem/28941679>
+
+        Reviewed by Sam Weinig.
+
+        Import test coverage from WPT upstream.
+
+        * resources/import-expectations.json:
+        * web-platform-tests/common/PrefixedLocalStorage.js: Added.
+        (PrefixedLocalStorage):
+        (PrefixedLocalStorage.prototype.clear):
+        (PrefixedLocalStorage.prototype.url):
+        (PrefixedLocalStorage.prototype.prefixedKey):
+        (PrefixedLocalStorage.prototype.setItem):
+        (PrefixedLocalStorage.prototype.onSet):
+        (PrefixedLocalStorageTest):
+        (PrefixedLocalStorageTest.prototype.cleanup):
+        (PrefixedLocalStorageResource):
+        * web-platform-tests/common/w3c-import.log:
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed-expected.txt: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed.html: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-expected.txt: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple-expected.txt: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple.html: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener-expected.txt: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener.html: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer-expected.txt: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer.html: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener.html: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/close-opener.html: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/message-window-opener.html: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/multiple-opener.html: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/no-opener.html: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/open-closer.html: Added.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/w3c-import.log: Copied from LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/w3c-import.log.
+        * web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/w3c-import.log:
+
 2017-03-20  Jon Lee  <jonlee@apple.com>
 
         Update progression in wpt test for WebRTC.
index b65824c..a4acd84 100644 (file)
     "web-platform-tests/browser-payment-api": "skip", 
     "web-platform-tests/clear-site-data": "skip", 
     "web-platform-tests/clipboard": "skip", 
+    "web-platform-tests/common/": "import", 
     "web-platform-tests/compat": "skip", 
     "web-platform-tests/console": "skip", 
     "web-platform-tests/content-security-policy": "skip", 
     "web-platform-tests/html/browsers/offline/application-cache-api": "skip", 
     "web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.sub.html": "skip", 
     "web-platform-tests/html/browsers/sandboxing": "skip", 
+    "web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/": "import", 
     "web-platform-tests/html/browsers/windows/browsing-context-first-created.xhtml": "skip", 
     "web-platform-tests/html/browsers/windows/nested-browsing-contexts/frameElement.html": "skip", 
     "web-platform-tests/html/browsers/windows/targeting-cross-origin-nested-browsing-contexts.html": "skip", 
diff --git a/LayoutTests/imported/w3c/web-platform-tests/common/PrefixedLocalStorage.js b/LayoutTests/imported/w3c/web-platform-tests/common/PrefixedLocalStorage.js
new file mode 100644 (file)
index 0000000..2f4e7b6
--- /dev/null
@@ -0,0 +1,116 @@
+/**
+ * Supports pseudo-"namespacing" localStorage for a given test
+ * by generating and using a unique prefix for keys. Why trounce on other
+ * tests' localStorage items when you can keep it "separated"?
+ *
+ * PrefixedLocalStorageTest: Instantiate in testharness.js tests to generate
+ *   a new unique-ish prefix
+ * PrefixedLocalStorageResource: Instantiate in supporting test resource
+ *   files to use/share a prefix generated by a test.
+ */
+var PrefixedLocalStorage = function () {
+  this.prefix = ''; // Prefix for localStorage keys
+  this.param = 'prefixedLocalStorage'; // Param to use in querystrings
+};
+
+PrefixedLocalStorage.prototype.clear = function () {
+  if (this.prefix === '') { return; }
+  Object.keys(localStorage).forEach(sKey => {
+    if (sKey.indexOf(this.prefix) === 0) {
+      localStorage.removeItem(sKey);
+    }
+  });
+};
+
+/**
+ * Append/replace prefix parameter and value in URI querystring
+ * Use to generate URLs to resource files that will share the prefix.
+ */
+PrefixedLocalStorage.prototype.url = function (uri) {
+  function updateUrlParameter (uri, key, value) {
+    var i         = uri.indexOf('#');
+    var hash      = (i === -1) ? '' : uri.substr(i);
+    uri           = (i === -1) ? uri : uri.substr(0, i);
+    var re        = new RegExp(`([?&])${key}=.*?(&|$)`, 'i');
+    var separator = uri.indexOf('?') !== -1 ? '&' : '?';
+    uri = (uri.match(re)) ? uri.replace(re, `$1${key}=${value}$2`) :
+      `${uri}${separator}${key}=${value}`;
+    return uri + hash;
+  }
+  return updateUrlParameter(uri, this.param, this.prefix);
+};
+
+PrefixedLocalStorage.prototype.prefixedKey = function (baseKey) {
+  return `${this.prefix}${baseKey}`;
+};
+
+PrefixedLocalStorage.prototype.setItem = function (baseKey, value) {
+  localStorage.setItem(this.prefixedKey(baseKey), value);
+};
+
+/**
+ * Listen for `storage` events pertaining to a particular key,
+ * prefixed with this object's prefix. Ignore when value is being set to null
+ * (i.e. removeItem).
+ */
+PrefixedLocalStorage.prototype.onSet = function (baseKey, fn) {
+  window.addEventListener('storage', e => {
+    var match = this.prefixedKey(baseKey);
+    if (e.newValue !== null && e.key.indexOf(match) === 0) {
+      fn.call(this, e);
+    }
+  });
+};
+
+/*****************************************************************************
+ * Use in a testharnessjs test to generate a new key prefix.
+ * async_test(t => {
+ *   var prefixedStorage = new PrefixedLocalStorageTest();
+ *   t.add_cleanup(() => prefixedStorage.cleanup());
+ *   /...
+ * });
+ */
+var PrefixedLocalStorageTest = function () {
+  PrefixedLocalStorage.call(this);
+  this.prefix = `${document.location.pathname}-${Math.random()}-${Date.now()}-`;
+};
+PrefixedLocalStorageTest.prototype = Object.create(PrefixedLocalStorage.prototype);
+PrefixedLocalStorageTest.prototype.constructor = PrefixedLocalStorageTest;
+
+/**
+ * Use in a cleanup function to clear out prefixed entries in localStorage
+ */
+PrefixedLocalStorageTest.prototype.cleanup = function () {
+  this.setItem('closeAll', 'true');
+  this.clear();
+};
+
+/*****************************************************************************
+ * Use in test resource files to share a prefix generated by a
+ * PrefixedLocalStorageTest. Will look in URL querystring for prefix.
+ * Setting `close_on_cleanup` opt truthy will make this script's window listen
+ * for storage `closeAll` event from controlling test and close itself.
+ *
+ * var PrefixedLocalStorageResource({ close_on_cleanup: true });
+ */
+var PrefixedLocalStorageResource = function (options) {
+  PrefixedLocalStorage.call(this);
+  this.options = Object.assign({}, {
+    close_on_cleanup: false
+  }, options || {});
+  // Check URL querystring for prefix to use
+  var regex = new RegExp(`[?&]${this.param}(=([^&#]*)|&|#|$)`),
+    results = regex.exec(document.location.href);
+  if (results && results[2]) {
+    this.prefix = results[2];
+  }
+  // Optionally have this window close itself when the PrefixedLocalStorageTest
+  // sets a `closeAll` item.
+  if (this.options.close_on_cleanup) {
+    this.onSet('closeAll', () => {
+      window.close();
+    });
+  }
+};
+PrefixedLocalStorageResource.prototype = Object.create(PrefixedLocalStorage.prototype);
+PrefixedLocalStorageResource.prototype.constructor = PrefixedLocalStorageResource;
index 7e142ab..a8dde3e 100644 (file)
@@ -16,6 +16,7 @@ None
 ------------------------------------------------------------------------
 List of files:
 /LayoutTests/imported/w3c/web-platform-tests/common/OWNERS
+/LayoutTests/imported/w3c/web-platform-tests/common/PrefixedLocalStorage.js
 /LayoutTests/imported/w3c/web-platform-tests/common/blank.html
 /LayoutTests/imported/w3c/web-platform-tests/common/canvas-frame.css
 /LayoutTests/imported/w3c/web-platform-tests/common/canvas-index.css
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed-expected.txt
new file mode 100644 (file)
index 0000000..88e0b6f
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS An auxiliary browsing context should report `null` for `window.opener` when that browsing context is discarded 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed.html b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed.html
new file mode 100644 (file)
index 0000000..5a15d9f
--- /dev/null
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<html>
+  <head>
+    <title>Auxiliary Browing Contexts: window.opener when Opener Removed/Closed</title>
+    <script src="../../../../../../../resources/testharness.js"></script>
+    <script src="../../../../../../../resources/testharnessreport.js"></script>
+    <script src="/common/PrefixedLocalStorage.js"></script>
+  </head>
+  <body>
+    <div id="log"></div>
+    <script>
+    var prefixedLocalStorage;
+    setup (() => prefixedLocalStorage = new PrefixedLocalStorageTest());
+    async_test(t => {
+      t.add_cleanup (() => prefixedLocalStorage.cleanup());
+      var a       = document.createElement('a');
+      a.href      = prefixedLocalStorage.url('resources/open-closer.html');
+      a.target    = '_blank';
+      prefixedLocalStorage.onSet('openerIsNull', t.step_func_done(e => {
+        // The window for this auxiliary browsing context's opener
+        // has been closed and discarded, so the aux browsing context
+        // should now report `null` for `window.opener`
+        assert_equals(e.newValue, 'true');
+      }));
+      document.body.append(a);
+      a.click();
+    }, 'An auxiliary browsing context should report `null` for `window.opener` when that browsing context is discarded');
+    </script>
+  </body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-expected.txt
new file mode 100644 (file)
index 0000000..4278477
--- /dev/null
@@ -0,0 +1,4 @@
+
+PASS Newly-created auxiliary browsing context should report `window.opener` 
+PASS Browsing context created with `window.open` should report `window.opener` 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple-expected.txt
new file mode 100644 (file)
index 0000000..d53391b
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS An auxiliary browsing context should be able to open another auxiliary browsing context 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple.html b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple.html
new file mode 100644 (file)
index 0000000..73ced25
--- /dev/null
@@ -0,0 +1,35 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Auxiliary Browing Contexts: window.opener, multiple</title>
+    <script src="../../../../../../../resources/testharness.js"></script>
+    <script src="../../../../../../../resources/testharnessreport.js"></script>
+    <script src="/common/PrefixedLocalStorage.js"></script>
+  </head>
+  <body>
+    <div id="log"></div>
+    <script>
+    var prefixedLocalStorage;
+    setup (() => prefixedLocalStorage = new PrefixedLocalStorageTest());
+    async_test(t => {
+      t.add_cleanup (() => prefixedLocalStorage.cleanup());
+      var a       = document.createElement('a');
+      a.href      = prefixedLocalStorage.url('resources/multiple-opener.html');
+      a.target    = 'multipleOpener';
+      window.name = 'topOpener';
+      document.body.appendChild(a);
+      window.addEventListener('message', t.step_func_done(e => {
+        var aux1 = e.data.aux1; // First opened context
+        var aux2 = e.data.aux2; // Context opened by first-opened context
+        assert_equals(aux1.name, 'multipleOpener');
+        assert_equals(aux1.openerName, window.name);
+        assert_equals(aux1.isTop, true);
+        assert_equals(aux2.name, 'multipleOpenee');
+        assert_equals(aux2.openerName, aux1.name);
+        assert_equals(aux2.isTop, true);
+      }));
+      a.click();
+    }, 'An auxiliary browsing context should be able to open another auxiliary browsing context');
+    </script>
+  </body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener-expected.txt
new file mode 100644 (file)
index 0000000..3d1f5bf
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS Auxiliary browsing context created via `window.open` setting `noopener` should report `window.opener` `null` 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener.html b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener.html
new file mode 100644 (file)
index 0000000..108a4ee
--- /dev/null
@@ -0,0 +1,25 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Auxiliary Browing Contexts: window.opener noopener</title>
+    <script src="../../../../../../../resources/testharness.js"></script>
+    <script src="../../../../../../../resources/testharnessreport.js"></script>
+    <script src="/common/PrefixedLocalStorage.js"></script>
+  </head>
+  <body>
+    <div id="log"></div>
+    <script>
+    var prefixedLocalStorage;
+    setup(() => prefixedLocalStorage = new PrefixedLocalStorageTest());
+    async_test(t => {
+      t.add_cleanup(() => prefixedLocalStorage.cleanup());
+      prefixedLocalStorage.onSet('openerIsNull', t.step_func_done(e => {
+        assert_equals(e.newValue, 'true');
+      }));
+      window.open(prefixedLocalStorage.url('resources/no-opener.html'),
+        'iShouldNotHaveAnOpener',
+        'noopener');
+    }, 'Auxiliary browsing context created via `window.open` setting `noopener` should report `window.opener` `null`');
+    </script>
+  </body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer-expected.txt
new file mode 100644 (file)
index 0000000..379ed32
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS Auxiliary browsing context created with `rel="noreferrer"` should report `window.opener` `null` 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer.html b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer.html
new file mode 100644 (file)
index 0000000..46e8d38
--- /dev/null
@@ -0,0 +1,29 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Auxiliary Browing Contexts: window.opener noreferrer</title>
+    <script src="../../../../../../../resources/testharness.js"></script>
+    <script src="../../../../../../../resources/testharnessreport.js"></script>
+    <script src="/common/PrefixedLocalStorage.js"></script>
+  </head>
+  <body>
+    <div id="log"></div>
+    <script>
+    var prefixedLocalStorage;
+    setup(() => prefixedLocalStorage = new PrefixedLocalStorageTest());
+    async_test(t => {
+      t.add_cleanup(() => prefixedLocalStorage.cleanup());
+      var a       = document.createElement('a');
+      a.href      = prefixedLocalStorage.url('resources/no-opener.html');
+      a.target    = '_blank';
+      a.rel       = 'noreferrer';
+      window.name = 'topWindow';
+      document.body.appendChild(a);
+      prefixedLocalStorage.onSet('openerIsNull', t.step_func_done(e => {
+        assert_equals(e.newValue, 'true');
+      }));
+      a.click();
+    }, 'Auxiliary browsing context created with `rel="noreferrer"` should report `window.opener` `null`');
+    </script>
+  </body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener.html b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener.html
new file mode 100644 (file)
index 0000000..ff9fe6b
--- /dev/null
@@ -0,0 +1,55 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Auxiliary Browing Contexts: window.opener</title>
+    <script src="../../../../../../../resources/testharness.js"></script>
+    <script src="../../../../../../../resources/testharnessreport.js"></script>
+    <script src="/common/PrefixedLocalStorage.js"></script>
+  </head>
+  <body>
+    <div id="log"></div>
+    <script>
+    var prefixedLocalStorage;
+    setup (() => {
+      window.name = 'topWindow';
+      prefixedLocalStorage = new PrefixedLocalStorageTest();
+    });
+
+    function cleanup () {
+      prefixedLocalStorage.setItem('closeAll', 'true');
+      prefixedLocalStorage.clear();
+    }
+
+    function testOpener (t, target) {
+      t.add_cleanup(cleanup);
+      window.addEventListener('message', t.step_func(e => {
+        if (e.data.name === target) {
+          // The opener IDL attribute...must return the WindowProxy object of the
+          // browsing context from which the current browsing context was created
+          assert_equals(e.data.openerName, 'topWindow');
+          // Auxiliary browsing contexts are always top-level browsing contexts
+          assert_equals(e.data.isTop, true);
+          t.done();
+        }
+      }));
+    }
+
+    async_test(t => {
+      var target = 'windowOpenerA';
+      var a      = document.createElement('a');
+      a.href     = prefixedLocalStorage.url('resources/message-window-opener.html');
+      a.target   = target;
+      document.body.appendChild(a);
+      testOpener(t, target);
+      a.click();
+    }, 'Newly-created auxiliary browsing context should report `window.opener`');
+
+    async_test(t => {
+      var target = 'windowOpenerB';
+      testOpener(t, target);
+      window.open(prefixedLocalStorage.url('resources/message-window-opener.html'),
+        target);
+    }, 'Browsing context created with `window.open` should report `window.opener`');
+    </script>
+  </body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/close-opener.html b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/close-opener.html
new file mode 100644 (file)
index 0000000..f41773e
--- /dev/null
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<html>
+<body onload="closeOpener()">
+<p>This window should close its opener.</p>
+<script src="/common/PrefixedLocalStorage.js"></script>
+<script>
+var prefixedLocalStorage = new PrefixedLocalStorageResource({
+  close_on_cleanup: true
+});
+var prefixedLocalStorage = new PrefixedLocalStorageResource({
+  close_on_cleanup: true
+});
+function closeOpener () {
+  if (window.opener) {
+    window.opener.close();
+
+    // Give the browsing context a chance to dispose of itself
+    function waitForContextDiscard () {
+      if (window.opener === null) {
+        return prefixedLocalStorage.setItem('openerIsNull', 'true');
+      }
+      return setTimeout(waitForContextDiscard, 0);
+    }
+    waitForContextDiscard();
+  }
+}
+</script>
+</body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/message-window-opener.html b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/message-window-opener.html
new file mode 100644 (file)
index 0000000..8105650
--- /dev/null
@@ -0,0 +1,14 @@
+<script src="/common/PrefixedLocalStorage.js"></script>
+<script>
+var prefixedLocalStorage = new PrefixedLocalStorageResource({
+  close_on_cleanup: true
+});
+
+if (window.opener) {
+  window.opener.postMessage ({
+    name      : window.name,
+    openerName: window.opener.name,
+    isTop     : window.top === window
+  }, '*');
+}
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/multiple-opener.html b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/multiple-opener.html
new file mode 100644 (file)
index 0000000..2e63b9f
--- /dev/null
@@ -0,0 +1,32 @@
+<!doctype html>
+<html>
+<script src="/common/PrefixedLocalStorage.js"></script>
+<body onload="openNested()">
+<script>
+var prefixedLocalStorage = new PrefixedLocalStorageResource({
+  close_on_cleanup: true
+});
+function openNested () {
+  // Listen for message from opened context and pass through to this
+  // context's opener
+  window.addEventListener('message', (e) => {
+    if (window.opener) {
+      window.opener.postMessage({
+        aux2: e.data, // From multipleOpenee
+        aux1: { // This context
+          name               : window.name,
+          openerName         : window.opener.name,
+          isTop              : window.top === window
+        }
+      }, '*');
+    }
+  });
+  var a = document.createElement('a');
+  a.target = 'multipleOpenee';
+  a.href = prefixedLocalStorage.url('message-window-opener.html');
+  document.body.appendChild(a);
+  a.click();
+}
+</script>
+</body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/no-opener.html b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/no-opener.html
new file mode 100644 (file)
index 0000000..afd72f9
--- /dev/null
@@ -0,0 +1,16 @@
+<!doctype html>
+<meta charset="utf-8">
+<html>
+<p>This window should have no opener.</p>
+<script src="/common/PrefixedLocalStorage.js"></script>
+<script>
+var prefixedLocalStorage = new PrefixedLocalStorageResource({
+  close_on_cleanup: true
+});
+function checkOpener () {
+  return prefixedLocalStorage.setItem('openerIsNull', window.opener === null);
+}
+</script>
+<body onload="checkOpener()">
+</body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/open-closer.html b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/open-closer.html
new file mode 100644 (file)
index 0000000..6f43a51
--- /dev/null
@@ -0,0 +1,17 @@
+<!doctype html>
+<meta charset="utf-8">
+<html>
+<body onload="openAuxiliary()">
+<a target="_blank">Open auxiliary context that will close this window (its opener)</a>
+<script src="/common/PrefixedLocalStorage.js"></script>
+<script>
+function openAuxiliary () {
+  var prefixedLocalStorage = new PrefixedLocalStorageResource();
+  var a = document.body.querySelector('a');
+  a.href = prefixedLocalStorage.url('close-opener.html');
+  document.body.append(a);
+  a.click();
+}
+</script>
+</body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/w3c-import.log
new file mode 100644 (file)
index 0000000..c13a2bb
--- /dev/null
@@ -0,0 +1,22 @@
+The tests in this directory were imported from the W3C repository.
+Do NOT modify these tests directly in WebKit.
+Instead, create a pull request on the W3C CSS or WPT github:
+       https://github.com/w3c/csswg-test
+       https://github.com/w3c/web-platform-tests
+
+Then run the Tools/Scripts/import-w3c-tests in WebKit to reimport
+
+Do NOT modify or remove this file.
+
+------------------------------------------------------------------------
+Properties requiring vendor prefixes:
+None
+Property values requiring vendor prefixes:
+None
+------------------------------------------------------------------------
+List of files:
+/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/close-opener.html
+/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/message-window-opener.html
+/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/multiple-opener.html
+/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/no-opener.html
+/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/resources/open-closer.html
index f988146..f758bf1 100644 (file)
@@ -16,3 +16,8 @@ None
 ------------------------------------------------------------------------
 List of files:
 /LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/contains.json
+/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed.html
+/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple.html
+/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener.html
+/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer.html
+/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener.html
index 4953170..3d6d3fd 100644 (file)
@@ -1,3 +1,27 @@
+2017-03-22  Chris Dumez  <cdumez@apple.com>
+
+        Implement the "noopener" feature for window.open()
+        https://bugs.webkit.org/show_bug.cgi?id=163960
+        <rdar://problem/28941679>
+
+        Reviewed by Sam Weinig.
+
+        Implement the "noopener" feature for window.open(). If 'noopener' is passed to window.open()
+        then the new Window's opener property will be null.
+
+        Tests: imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-closed.html
+               imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-multiple.html
+               imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener.html
+               imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener-noreferrer.html
+               imported/w3c/web-platform-tests/html/browsers/windows/auxiliary-browsing-contexts/opener.html
+
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::createWindow):
+        * page/WindowFeatures.cpp:
+        (WebCore::parseWindowFeatures):
+        (WebCore::setWindowFeature):
+        * page/WindowFeatures.h:
+
 2017-03-21  Sergio Villar Senin  <svillar@igalia.com>
 
         [Soup] "Only from websites I visit" cookie policy is broken
index 2fb1508..9ee7f96 100644 (file)
@@ -2198,7 +2198,8 @@ RefPtr<Frame> DOMWindow::createWindow(const String& urlString, const AtomicStrin
     if (!newFrame)
         return nullptr;
 
-    newFrame->loader().setOpener(&openerFrame);
+    if (!windowFeatures.noopener)
+        newFrame->loader().setOpener(&openerFrame);
     newFrame->page()->setOpenedByDOM();
 
     if (newFrame->document()->domWindow()->isInsecureScriptAccess(activeWindow, completedURL))
index b8adcb4..b8944ed 100644 (file)
@@ -63,6 +63,7 @@ WindowFeatures parseWindowFeatures(StringView featuresString)
     features.toolBarVisible = false;
     features.locationBarVisible = false;
     features.scrollbarsVisible = false;
+    features.noopener = false;
 
     processFeaturesString(featuresString, [&features](StringView key, StringView value) {
         setWindowFeature(features, key, value);
@@ -135,6 +136,8 @@ static void setWindowFeature(WindowFeatures& features, StringView key, StringVie
         features.fullscreen = numericValue;
     else if (equalLettersIgnoringASCIICase(key, "scrollbars"))
         features.scrollbarsVisible = numericValue;
+    else if (equalLettersIgnoringASCIICase(key, "noopener"))
+        features.noopener = numericValue;
     else if (numericValue == 1)
         features.additionalFeatures.append(key.toString());
 }
index d46a75a..f7eb5fe 100644 (file)
@@ -52,6 +52,7 @@ struct WindowFeatures {
 
     bool fullscreen { false };
     bool dialog { false };
+    bool noopener { false };
 
     Vector<String> additionalFeatures;
 };