Title: [197528] trunk
Revision
197528
Author
[email protected]
Date
2016-03-03 16:28:44 -0800 (Thu, 03 Mar 2016)

Log Message

Source/WebCore:
Disallow custom elements inside a window-less documents
https://bugs.webkit.org/show_bug.cgi?id=154944
<rdar://problem/24944875>

Reviewed by Antti Koivisto.

Disallow custom elements inside a window-less documents such as the shared inert document of template elements
and the ones created by DOMImplementation.createDocument and DOMImplementation.createHTMLDocument.

Throw NotSupportedError in defineCustomElement when it's called in such a document as discussed in:
https://github.com/w3c/webcomponents/issues/369

Tests: fast/custom-elements/parser/parser-constructs-custom-element-in-document-write.html
       fast/custom-elements/parser/parser-uses-registry-of-owner-document.html

* bindings/js/JSDOMBinding.cpp:
(WebCore::throwNotSupportedError): Added.
* bindings/js/JSDOMBinding.h:
* bindings/js/JSDocumentCustom.cpp:
(WebCore::JSDocument::defineCustomElement): Throw NotSupportedError when the context object's document doesn't
have a browsing context (i.e. window-less).
* html/parser/HTMLDocumentParser.cpp:
(WebCore::HTMLDocumentParser::runScriptsForPausedTreeBuilder): Replaced a FIXME with an assertion now that we
disallow instantiation of custom elements inside a template element.

LayoutTests:
Disallow custom elements inside template elements and share the registry for windowless documents
https://bugs.webkit.org/show_bug.cgi?id=154944
<rdar://problem/24944875>

Reviewed by Antti Koivisto.

Added various tests to ensure the custom elements registry is not shared between documents with
distinct browsing context (e.g. iframes) but shared among the ones that share a single browsing context
(e.g. documents created by DOMImplementation).

Also added a test case for defineCustomElement to ensure it throws NotSupportedError when it's called on
a template element's inert owner document as well as a basic test case for document.write.

* fast/custom-elements/Document-defineCustomElement-expected.txt:
* fast/custom-elements/Document-defineCustomElement.html: Added a new test case.
* fast/custom-elements/parser/parser-constructs-custom-element-in-document-write-expected.txt: Added.
* fast/custom-elements/parser/parser-constructs-custom-element-in-document-write.html: Added.
* fast/custom-elements/parser/parser-uses-registry-of-owner-document-expected.txt: Added.
* fast/custom-elements/parser/parser-uses-registry-of-owner-document.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (197527 => 197528)


--- trunk/LayoutTests/ChangeLog	2016-03-04 00:26:23 UTC (rev 197527)
+++ trunk/LayoutTests/ChangeLog	2016-03-04 00:28:44 UTC (rev 197528)
@@ -1,3 +1,25 @@
+2016-03-02  Ryosuke Niwa  <[email protected]>
+
+        Disallow custom elements inside template elements and share the registry for windowless documents
+        https://bugs.webkit.org/show_bug.cgi?id=154944
+        <rdar://problem/24944875>
+
+        Reviewed by Antti Koivisto.
+
+        Added various tests to ensure the custom elements registry is not shared between documents with
+        distinct browsing context (e.g. iframes) but shared among the ones that share a single browsing context
+        (e.g. documents created by DOMImplementation).
+
+        Also added a test case for defineCustomElement to ensure it throws NotSupportedError when it's called on
+        a template element's inert owner document as well as a basic test case for document.write.
+
+        * fast/custom-elements/Document-defineCustomElement-expected.txt:
+        * fast/custom-elements/Document-defineCustomElement.html: Added a new test case.
+        * fast/custom-elements/parser/parser-constructs-custom-element-in-document-write-expected.txt: Added.
+        * fast/custom-elements/parser/parser-constructs-custom-element-in-document-write.html: Added.
+        * fast/custom-elements/parser/parser-uses-registry-of-owner-document-expected.txt: Added.
+        * fast/custom-elements/parser/parser-uses-registry-of-owner-document.html: Added.
+
 2016-03-03  Zalan Bujtas  <[email protected]>
 
         Subpixel rendering: Make collapsed borders painting subpixel aware.

Modified: trunk/LayoutTests/fast/custom-elements/Document-defineCustomElement-expected.txt (197527 => 197528)


--- trunk/LayoutTests/fast/custom-elements/Document-defineCustomElement-expected.txt	2016-03-04 00:26:23 UTC (rev 197527)
+++ trunk/LayoutTests/fast/custom-elements/Document-defineCustomElement-expected.txt	2016-03-04 00:28:44 UTC (rev 197528)
@@ -2,6 +2,9 @@
 PASS Check the existence of defineCustomElement on Document interface 
 PASS document.defineCustomElement should throw with an invalid name 
 PASS document.defineCustomElement should throw with a duplicate name 
+PASS document.defineCustomElement must throw a NotSupportedError when the context object is an associated inert template document 
+PASS document.defineCustomElement must throw a NotSupportedError when the context object is created by DOMImplementation.createHTMLDocument 
+PASS document.defineCustomElement must throw a NotSupportedError when the context object is created by DOMImplementation.createDocument 
 PASS document.defineCustomElement should throw when the element interface is not a constructor 
 PASS document.defineCustomElement should define an instantiatable custom element 
 

Modified: trunk/LayoutTests/fast/custom-elements/Document-defineCustomElement.html (197527 => 197528)


--- trunk/LayoutTests/fast/custom-elements/Document-defineCustomElement.html	2016-03-04 00:26:23 UTC (rev 197527)
+++ trunk/LayoutTests/fast/custom-elements/Document-defineCustomElement.html	2016-03-04 00:28:44 UTC (rev 197528)
@@ -58,6 +58,36 @@
 }, 'document.defineCustomElement should throw with a duplicate name');
 
 test(function () {
+    class SomeCustomElement extends HTMLElement {};
+
+    var templateContentOwnerDocument = document.createElement('template').content.ownerDocument;
+    assert_throws({'name': 'NotSupportedError'}, function () {
+        templateContentOwnerDocument.defineCustomElement('some-custom-element', SomeCustomElement);
+    });
+
+}, 'document.defineCustomElement must throw a NotSupportedError when the context object is an associated inert template document');
+
+test(function () {
+    class SomeCustomElement extends HTMLElement {};
+
+    var windowlessDocument = document.implementation.createHTMLDocument();
+    assert_throws({'name': 'NotSupportedError'}, function () {
+        windowlessDocument.defineCustomElement('some-custom-element', SomeCustomElement);
+    });
+
+}, 'document.defineCustomElement must throw a NotSupportedError when the context object is created by DOMImplementation.createHTMLDocument');
+
+test(function () {
+    class SomeCustomElement extends HTMLElement {};
+
+    var windowlessDocument = document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', null)
+    assert_throws({'name': 'NotSupportedError'}, function () {
+        windowlessDocument.defineCustomElement('some-custom-element', SomeCustomElement);
+    });
+
+}, 'document.defineCustomElement must throw a NotSupportedError when the context object is created by DOMImplementation.createDocument');
+
+test(function () {
     assert_throws({'name': 'TypeError'}, function () { document.defineCustomElement('invalid-element', 1); },
         'document.defineCustomElement must throw a TypeError when the element interface is a number');
     assert_throws({'name': 'TypeError'}, function () { document.defineCustomElement('invalid-element', '123'); },

Added: trunk/LayoutTests/fast/custom-elements/parser/parser-constructs-custom-element-in-document-write-expected.txt (0 => 197528)


--- trunk/LayoutTests/fast/custom-elements/parser/parser-constructs-custom-element-in-document-write-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/parser/parser-constructs-custom-element-in-document-write-expected.txt	2016-03-04 00:28:44 UTC (rev 197528)
@@ -0,0 +1,3 @@
+
+PASS HTML parser must instantiate custom elements inside document.write 
+

Added: trunk/LayoutTests/fast/custom-elements/parser/parser-constructs-custom-element-in-document-write.html (0 => 197528)


--- trunk/LayoutTests/fast/custom-elements/parser/parser-constructs-custom-element-in-document-write.html	                        (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/parser/parser-constructs-custom-element-in-document-write.html	2016-03-04 00:28:44 UTC (rev 197528)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Custom Elements: Changes to the HTML parser</title>
+<meta name="author" title="Ryosuke Niwa" href=""
+<meta name="assert" content="HTML parser must construct custom elements inside document.write">
+<script src=""
+<script src=""
+<link rel='stylesheet' href=''>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+class MyCustomElement extends HTMLElement { }
+document.defineCustomElement('my-custom-element', MyCustomElement);
+
+document.write('<my-custom-element></my-custom-element>');
+
+test(function () {
+    var instance = document.querySelector('my-custom-element');
+
+    assert_true(instance instanceof HTMLElement);
+    assert_true(instance instanceof MyCustomElement);
+
+}, 'HTML parser must instantiate custom elements inside document.write');
+
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/fast/custom-elements/parser/parser-uses-registry-of-owner-document-expected.txt (0 => 197528)


--- trunk/LayoutTests/fast/custom-elements/parser/parser-uses-registry-of-owner-document-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/parser/parser-uses-registry-of-owner-document-expected.txt	2016-03-04 00:28:44 UTC (rev 197528)
@@ -0,0 +1,8 @@
+
+PASS HTML parser must not instantiate custom elements inside template elements 
+PASS HTML parser must not use the registry of the owner element's document inside an iframe 
+PASS HTML parser must use the registry of the content document inside an iframe 
+PASS HTML parser must not instantiate a custom element defined inside an frame in frame element's owner document 
+PASS HTML parser must use the registry of window.document in a document created by document.implementation.createHTMLDocument() 
+PASS HTML parser must use the registry of window.document in a document created by document.implementation.createXHTMLDocument() 
+

Added: trunk/LayoutTests/fast/custom-elements/parser/parser-uses-registry-of-owner-document.html (0 => 197528)


--- trunk/LayoutTests/fast/custom-elements/parser/parser-uses-registry-of-owner-document.html	                        (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/parser/parser-uses-registry-of-owner-document.html	2016-03-04 00:28:44 UTC (rev 197528)
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Custom Elements: Changes to the HTML parser</title>
+<meta name="author" title="Ryosuke Niwa" href=""
+<meta name="assert" content="HTML parser must use the owner document's custom element registry">
+<script src=""
+<script src=""
+<link rel='stylesheet' href=''>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+class MyCustomElement extends HTMLElement { };
+document.defineCustomElement('my-custom-element', MyCustomElement);
+
+document.write('<template><my-custom-element></my-custom-element></template>');
+
+test(function () {
+    var template = document.querySelector('template');
+    var instance = template.content.firstChild;
+
+    assert_true(instance instanceof HTMLElement,
+        'A custom element inside a template element must be an instance of HTMLElement');
+    assert_false(instance instanceof MyCustomElement,
+        'A custom element must not be instantiated inside a template element using the registry of the template element\'s owner document');
+    assert_equals(instance.ownerDocument, template.content.ownerDocument,
+        'Custom elements inside a template must use the appropriate template contents owner document as the owner document');
+
+}, 'HTML parser must not instantiate custom elements inside template elements');
+
+var iframe = document.createElement('iframe');
+document.body.appendChild(iframe);
+iframe.contentDocument.body.innerHTML = '<my-custom-element></my-custom-element>';
+
+test(function () {
+    var instance = iframe.contentDocument.querySelector('my-custom-element');
+
+    assert_true(instance instanceof iframe.contentWindow.HTMLElement);
+    assert_false(instance instanceof MyCustomElement);
+
+}, 'HTML parser must not use the registry of the owner element\'s document inside an iframe');
+
+class ElementInIFrame extends iframe.contentWindow.HTMLElement { };
+iframe.contentDocument.defineCustomElement('element-in-iframe', ElementInIFrame);
+iframe.contentDocument.body.innerHTML = '<element-in-iframe></element-in-iframe>';
+
+test(function () {
+    var instance = iframe.contentDocument.querySelector('element-in-iframe');
+
+    assert_true(instance instanceof iframe.contentWindow.HTMLElement, 'A custom element inside an iframe must be an instance of HTMLElement');
+    assert_true(instance instanceof ElementInIFrame,
+        'A custom element must be instantiated inside an iframe using the registry of the content document');
+    assert_equals(instance.ownerDocument, iframe.contentDocument,
+        'The owner document of custom elements inside an iframe must be the content document of the iframe');
+
+}, 'HTML parser must use the registry of the content document inside an iframe');
+
+document.write('<element-in-iframe></element-in-iframe>');
+
+test(function () {
+    var instance = document.querySelector('element-in-iframe');
+
+    assert_true(instance instanceof HTMLElement);
+    assert_false(instance instanceof ElementInIFrame);
+
+}, 'HTML parser must not instantiate a custom element defined inside an frame in frame element\'s owner document');
+
+document.body.removeChild(iframe);
+
+var windowlessDocument = document.implementation.createHTMLDocument();
+windowlessDocument.open();
+windowlessDocument.write('<my-custom-element></my-custom-element>');
+windowlessDocument.close();
+
+test(function () {
+    var instance = windowlessDocument.querySelector('my-custom-element');
+
+    assert_true(instance instanceof HTMLElement);
+    assert_false(instance instanceof MyCustomElement);
+
+}, 'HTML parser must use the registry of window.document in a document created by document.implementation.createHTMLDocument()');
+
+windowlessDocument = document.implementation.createDocument ('http://www.w3.org/1999/xhtml', 'html', null);
+windowlessDocument.documentElement.innerHTML = '<my-custom-element></my-custom-element>';
+
+test(function () {
+    var instance = windowlessDocument.querySelector('my-custom-element');
+
+    assert_true(instance instanceof HTMLElement);
+    assert_false(instance instanceof MyCustomElement);
+
+}, 'HTML parser must use the registry of window.document in a document created by document.implementation.createXHTMLDocument()');
+
+</script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (197527 => 197528)


--- trunk/Source/WebCore/ChangeLog	2016-03-04 00:26:23 UTC (rev 197527)
+++ trunk/Source/WebCore/ChangeLog	2016-03-04 00:28:44 UTC (rev 197528)
@@ -1,3 +1,30 @@
+2016-03-03  Ryosuke Niwa  <[email protected]>
+
+        Disallow custom elements inside a window-less documents
+        https://bugs.webkit.org/show_bug.cgi?id=154944
+        <rdar://problem/24944875>
+
+        Reviewed by Antti Koivisto.
+
+        Disallow custom elements inside a window-less documents such as the shared inert document of template elements
+        and the ones created by DOMImplementation.createDocument and DOMImplementation.createHTMLDocument.
+
+        Throw NotSupportedError in defineCustomElement when it's called in such a document as discussed in:
+        https://github.com/w3c/webcomponents/issues/369
+
+        Tests: fast/custom-elements/parser/parser-constructs-custom-element-in-document-write.html
+               fast/custom-elements/parser/parser-uses-registry-of-owner-document.html
+
+        * bindings/js/JSDOMBinding.cpp:
+        (WebCore::throwNotSupportedError): Added.
+        * bindings/js/JSDOMBinding.h:
+        * bindings/js/JSDocumentCustom.cpp:
+        (WebCore::JSDocument::defineCustomElement): Throw NotSupportedError when the context object's document doesn't
+        have a browsing context (i.e. window-less).
+        * html/parser/HTMLDocumentParser.cpp:
+        (WebCore::HTMLDocumentParser::runScriptsForPausedTreeBuilder): Replaced a FIXME with an assertion now that we
+        disallow instantiation of custom elements inside a template element.
+
 2016-03-03  Alex Christensen  <[email protected]>
 
         Move SPI to CFNetworkSPI.h

Modified: trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp (197527 => 197528)


--- trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp	2016-03-04 00:26:23 UTC (rev 197527)
+++ trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp	2016-03-04 00:28:44 UTC (rev 197528)
@@ -635,6 +635,13 @@
     context.addConsoleMessage(MessageSource::JS, MessageLevel::Error, makeString("Deprecated attempt to set property '", attributeName, "' on a non-", interfaceName, " object."));
 }
 
+void throwNotSupportedError(JSC::ExecState& state, const char* message)
+{
+    ASSERT(!state.hadException());
+    String messageString(message);
+    state.vm().throwException(&state, createDOMException(&state, NOT_SUPPORTED_ERR, &messageString));
+}
+
 JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::ExecState& state, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues)
 {
     StringBuilder builder;

Modified: trunk/Source/WebCore/bindings/js/JSDOMBinding.h (197527 => 197528)


--- trunk/Source/WebCore/bindings/js/JSDOMBinding.h	2016-03-04 00:26:23 UTC (rev 197527)
+++ trunk/Source/WebCore/bindings/js/JSDOMBinding.h	2016-03-04 00:28:44 UTC (rev 197528)
@@ -84,6 +84,7 @@
 WEBCORE_EXPORT JSC::EncodedJSValue reportDeprecatedGetterError(JSC::ExecState&, const char* interfaceName, const char* attributeName);
 WEBCORE_EXPORT void reportDeprecatedSetterError(JSC::ExecState&, const char* interfaceName, const char* attributeName);
 
+void throwNotSupportedError(JSC::ExecState&, const char* message);
 void throwArrayElementTypeError(JSC::ExecState&);
 void throwAttributeTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName, const char* expectedType);
 WEBCORE_EXPORT void throwSequenceTypeError(JSC::ExecState&);

Modified: trunk/Source/WebCore/bindings/js/JSDocumentCustom.cpp (197527 => 197528)


--- trunk/Source/WebCore/bindings/js/JSDocumentCustom.cpp	2016-03-04 00:26:23 UTC (rev 197527)
+++ trunk/Source/WebCore/bindings/js/JSDocumentCustom.cpp	2016-03-04 00:28:44 UTC (rev 197528)
@@ -147,6 +147,11 @@
         return throwTypeError(&state, "The second argument must be a constructor");
 
     Document& document = wrapped();
+    if (!document.domWindow()) {
+        throwNotSupportedError(state, "Cannot define a custom element in a docuemnt without a browsing context");
+        return jsUndefined();
+    }
+
     switch (CustomElementDefinitions::checkName(tagName)) {
     case CustomElementDefinitions::NameStatus::Valid:
         break;
@@ -161,10 +166,7 @@
     QualifiedName name(nullAtom, tagName, HTMLNames::xhtmlNamespaceURI);
     auto& definitions = document.ensureCustomElementDefinitions();
     if (definitions.findInterface(tagName)) {
-        ExceptionCodeWithMessage ec;
-        ec.code = NOT_SUPPORTED_ERR;
-        ec.message = "Cannot define multiple custom elements with the same tag name";
-        setDOMException(&state, ec);
+        throwNotSupportedError(state, "Cannot define multiple custom elements with the same tag name");
         return jsUndefined();
     }
     definitions.defineElement(name, JSCustomElementInterface::create(object, globalObject()));

Modified: trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp (197527 => 197528)


--- trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp	2016-03-04 00:26:23 UTC (rev 197527)
+++ trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp	2016-03-04 00:28:44 UTC (rev 197528)
@@ -196,7 +196,7 @@
 
         RefPtr<Element> newElement = constructionData->interface->constructElement(constructionData->name, JSCustomElementInterface::ShouldClearException::Clear);
         if (!newElement) {
-            // FIXME: This call to docuemnt() is wrong for elements inside a template element.
+            ASSERT(!m_treeBuilder->isParsingTemplateContents());
             newElement = HTMLUnknownElement::create(QualifiedName(nullAtom, constructionData->name, xhtmlNamespaceURI), *document());
         }
 

Modified: trunk/Source/WebCore/html/parser/HTMLTreeBuilder.h (197527 => 197528)


--- trunk/Source/WebCore/html/parser/HTMLTreeBuilder.h	2016-03-04 00:26:23 UTC (rev 197527)
+++ trunk/Source/WebCore/html/parser/HTMLTreeBuilder.h	2016-03-04 00:28:44 UTC (rev 197528)
@@ -61,6 +61,7 @@
 
     void constructTree(AtomicHTMLToken&);
 
+    bool isParsingTemplateContents() const;
     bool hasParserBlockingScriptWork() const;
 
     // Must be called to take the parser-blocking script before calling the parser again.
@@ -107,7 +108,6 @@
         AfterAfterFrameset,
     };
 
-    bool isParsingTemplateContents() const;
     bool isParsingFragmentOrTemplateContents() const;
 
 #if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to