Event handlers should not be called in frameless documents
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Jun 2017 03:48:23 +0000 (03:48 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Jun 2017 03:48:23 +0000 (03:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=173233

Reviewed by Sam Weinig.

LayoutTests/imported/w3c:

Rebaseline W3C test now that it is passing.

* web-platform-tests/html/webappapis/scripting/events/uncompiled_event_handler_with_scripting_disabled-expected.txt:

Source/WebCore:

As per the HTML specification [1], for event handlers on elements, we should use the
element's document to check if scripting is disabled [2]. Scripting is considered to
be disabled if the document has no browsing context (i.e. a frame in WebKit terms).

In JSLazyEventListener::initializeJSFunction(), instead of using the element's
document to do the checks, we would use the script execution context. In most cases,
a node's document and its script execution context are the same so this is not an
issue. However, if the node's document is a document created via JS, its nodes'
script execution context will be the document's context document (i.e the one that
created the document, see implementation of Node::scriptExecutionContext()). In those
cases, using the wrong document is an issue because the document's context document
(aka script execution context) may allow scripting but we still do not want to call
the event handler because its document is frameless.

This impacts documents created by JS, using the following APIs:
- DOMParser.parseFromHTML
- new Document()
- DOMImplementation.createDocument / createHTMLDocument
- XHRs whose responseType is Document.

[1] https://html.spec.whatwg.org/multipage/webappapis.html#getting-the-current-value-of-the-event-handler (step 1.1.)
[2] https://html.spec.whatwg.org/multipage/webappapis.html#concept-n-noscript

Tests: fast/events/event-handler-detached-document-dispatchEvent.html
       fast/events/event-handler-detached-document.html

* bindings/js/JSLazyEventListener.cpp:
(WebCore::JSLazyEventListener::initializeJSFunction):

LayoutTests:

Extend layout test coverage.

* fast/events/event-handler-detached-document-dispatchEvent-expected.txt: Added.
* fast/events/event-handler-detached-document-dispatchEvent.html: Added.
* fast/events/event-handler-detached-document-expected.txt: Added.
* fast/events/event-handler-detached-document.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/events/event-handler-detached-document-dispatchEvent-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/event-handler-detached-document-dispatchEvent.html [new file with mode: 0644]
LayoutTests/fast/events/event-handler-detached-document-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/event-handler-detached-document.html [new file with mode: 0644]
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/html/webappapis/scripting/events/uncompiled_event_handler_with_scripting_disabled-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSLazyEventListener.cpp

index 65d64fb..79c8a1e 100644 (file)
@@ -1,3 +1,17 @@
+2017-06-13  Chris Dumez  <cdumez@apple.com>
+
+        Event handlers should not be called in frameless documents
+        https://bugs.webkit.org/show_bug.cgi?id=173233
+
+        Reviewed by Sam Weinig.
+
+        Extend layout test coverage.
+
+        * fast/events/event-handler-detached-document-dispatchEvent-expected.txt: Added.
+        * fast/events/event-handler-detached-document-dispatchEvent.html: Added.
+        * fast/events/event-handler-detached-document-expected.txt: Added.
+        * fast/events/event-handler-detached-document.html: Added.
+
 2017-06-13  Antoine Quint  <graouts@apple.com>
 
         Rebaseline media/modern-media-controls/placard-support
diff --git a/LayoutTests/fast/events/event-handler-detached-document-dispatchEvent-expected.txt b/LayoutTests/fast/events/event-handler-detached-document-dispatchEvent-expected.txt
new file mode 100644 (file)
index 0000000..27ce7ba
--- /dev/null
@@ -0,0 +1,13 @@
+ALERT: PASS
+Tests that event handlers are not called in detached documents, even if the event is dispatched by JavaScript. This test passes if you do not see a FAIL alert message.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS video.__proto__ is HTMLVideoElement.prototype
+PASS video.__proto__ is HTMLVideoElement.prototype
+Adopting node into a document that has a frame
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/events/event-handler-detached-document-dispatchEvent.html b/LayoutTests/fast/events/event-handler-detached-document-dispatchEvent.html
new file mode 100644 (file)
index 0000000..c416aa9
--- /dev/null
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test.js"></script>
+<script>
+description("Tests that event handlers are not called in detached documents, even if the event is dispatched by JavaScript. This test passes if you do not see a FAIL alert message.");
+jsTestIsAsync = true;
+
+let doc = new DOMParser().parseFromString('<video src=x onerror=alert("FAIL1")>','text/html');
+let video = doc.body.firstChild;
+shouldBe("video.__proto__", "HTMLVideoElement.prototype");
+video.dispatchEvent(new CustomEvent("error"));
+
+doc = new DOMParser().parseFromString('<video onerror=alert(event.expected)>','text/html');
+video = doc.body.firstChild;
+shouldBe("video.__proto__", "HTMLVideoElement.prototype");
+let failEvent = new CustomEvent("error");
+failEvent.expected = "FAIL";
+video.dispatchEvent(failEvent);
+debug("Adopting node into a document that has a frame");
+document.adoptNode(video);
+let passEvent = new CustomEvent("error");
+passEvent.expected = "PASS";
+video.dispatchEvent(passEvent);
+
+
+setTimeout(finishJSTest, 0);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/events/event-handler-detached-document-expected.txt b/LayoutTests/fast/events/event-handler-detached-document-expected.txt
new file mode 100644 (file)
index 0000000..e72c7da
--- /dev/null
@@ -0,0 +1,9 @@
+Tests that event handlers are not called in detached documents. This test passes if you do not see a FAIL alert message.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/events/event-handler-detached-document.html b/LayoutTests/fast/events/event-handler-detached-document.html
new file mode 100644 (file)
index 0000000..152d9c3
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test.js"></script>
+<script>
+description("Tests that event handlers are not called in detached documents. This test passes if you do not see a FAIL alert message.");
+jsTestIsAsync = true;
+
+const payloads = [
+    '<video src=x onerror=alert("FAIL1")>',
+    '<audio src=x onerror=alert("FAIL2")>'
+];
+
+for (let payload of payloads) {
+    document.implementation.createHTMLDocument().write(payload);
+
+    new DOMParser().parseFromString(payload,'text/html');
+
+    var xhr = new XMLHttpRequest;
+    xhr.responseType = 'document';
+    xhr.open('GET', 'data:text/html,', false);
+    xhr.send(null);
+    xhr.response.body.innerHTML = payload;
+}
+
+setTimeout(finishJSTest, 0);
+</script>
+</body>
+</html>
index 3d87285..100b688 100644 (file)
@@ -1,3 +1,14 @@
+2017-06-13  Chris Dumez  <cdumez@apple.com>
+
+        Event handlers should not be called in frameless documents
+        https://bugs.webkit.org/show_bug.cgi?id=173233
+
+        Reviewed by Sam Weinig.
+
+        Rebaseline W3C test now that it is passing.
+
+        * web-platform-tests/html/webappapis/scripting/events/uncompiled_event_handler_with_scripting_disabled-expected.txt:
+
 2017-06-13  Matt Lewis  <jlewis3@apple.com>
 
         Re-baselined imported/w3c/web-platform-tests/WebCryptoAPI/import_export/test_rsa_importKey.https.html.
index 48a1ab3..3396fa2 100644 (file)
@@ -1,3 +1,39 @@
+2017-06-13  Chris Dumez  <cdumez@apple.com>
+
+        Event handlers should not be called in frameless documents
+        https://bugs.webkit.org/show_bug.cgi?id=173233
+
+        Reviewed by Sam Weinig.
+
+        As per the HTML specification [1], for event handlers on elements, we should use the
+        element's document to check if scripting is disabled [2]. Scripting is considered to
+        be disabled if the document has no browsing context (i.e. a frame in WebKit terms).
+
+        In JSLazyEventListener::initializeJSFunction(), instead of using the element's
+        document to do the checks, we would use the script execution context. In most cases,
+        a node's document and its script execution context are the same so this is not an
+        issue. However, if the node's document is a document created via JS, its nodes'
+        script execution context will be the document's context document (i.e the one that
+        created the document, see implementation of Node::scriptExecutionContext()). In those
+        cases, using the wrong document is an issue because the document's context document
+        (aka script execution context) may allow scripting but we still do not want to call
+        the event handler because its document is frameless.
+
+        This impacts documents created by JS, using the following APIs:
+        - DOMParser.parseFromHTML
+        - new Document()
+        - DOMImplementation.createDocument / createHTMLDocument
+        - XHRs whose responseType is Document.
+
+        [1] https://html.spec.whatwg.org/multipage/webappapis.html#getting-the-current-value-of-the-event-handler (step 1.1.)
+        [2] https://html.spec.whatwg.org/multipage/webappapis.html#concept-n-noscript
+
+        Tests: fast/events/event-handler-detached-document-dispatchEvent.html
+               fast/events/event-handler-detached-document.html
+
+        * bindings/js/JSLazyEventListener.cpp:
+        (WebCore::JSLazyEventListener::initializeJSFunction):
+
 2017-06-13  Antoine Quint  <graouts@apple.com>
 
         Rebaseline media/modern-media-controls/placard-support
index 9e051a9..cfcafef 100644 (file)
@@ -82,7 +82,11 @@ JSObject* JSLazyEventListener::initializeJSFunction(ScriptExecutionContext* exec
     if (m_code.isNull() || m_eventParameterName.isNull())
         return nullptr;
 
-    Document& document = downcast<Document>(*executionContext);
+    // As per the HTML specification [1], if this is an element's event handler, then document should be the
+    // element's document. The script execution context may be different from the node's document if the
+    // node's document was created by JavaScript.
+    // [1] https://html.spec.whatwg.org/multipage/webappapis.html#getting-the-current-value-of-the-event-handler
+    Document& document = m_originalNode ? m_originalNode->document() : downcast<Document>(*executionContext);
 
     if (!document.frame())
         return nullptr;