- Revision
- 205263
- Author
- [email protected]
- Date
- 2016-08-31 12:53:44 -0700 (Wed, 31 Aug 2016)
Log Message
HTML constructor must throw when newTarget is itself
https://bugs.webkit.org/show_bug.cgi?id=161430
Reviewed by Antti Koivisto.
Source/WebCore:
Per https://github.com/w3c/webcomponents/issues/541, we must throw a TypeError when the HTMLElement constructor
is called with new.target set to itself (i.e. new HTMLElement after registering it with a custom element).
Note that we can't check this at the time of customElements.define because it could be a Proxy object.
Also see: https://html.spec.whatwg.org/#html-element-constructors
Tests: fast/custom-elements/CustomElementRegistry.html
fast/custom-elements/HTMLElement-constructor.html
* bindings/js/JSHTMLElementCustom.cpp:
(WebCore::constructJSHTMLElement): Throw a TypeError when NewTarget is HTMLElement constructor itself.
LayoutTests:
Added test cases for defining a custom element with the HTMLElement constructor,
and making sure the HTMLElement constructor throws an exception when newTarget is itself.
* fast/custom-elements/CustomElementRegistry-expected.txt:
* fast/custom-elements/CustomElementRegistry.html:
* fast/custom-elements/HTMLElement-constructor-expected.txt:
* fast/custom-elements/HTMLElement-constructor.html:
Modified Paths
Diff
Modified: trunk/LayoutTests/ChangeLog (205262 => 205263)
--- trunk/LayoutTests/ChangeLog 2016-08-31 19:39:06 UTC (rev 205262)
+++ trunk/LayoutTests/ChangeLog 2016-08-31 19:53:44 UTC (rev 205263)
@@ -1,5 +1,20 @@
2016-08-31 Ryosuke Niwa <[email protected]>
+ HTML constructor must throw when newTarget is itself
+ https://bugs.webkit.org/show_bug.cgi?id=161430
+
+ Reviewed by Antti Koivisto.
+
+ Added test cases for defining a custom element with the HTMLElement constructor,
+ and making sure the HTMLElement constructor throws an exception when newTarget is itself.
+
+ * fast/custom-elements/CustomElementRegistry-expected.txt:
+ * fast/custom-elements/CustomElementRegistry.html:
+ * fast/custom-elements/HTMLElement-constructor-expected.txt:
+ * fast/custom-elements/HTMLElement-constructor.html:
+
+2016-08-31 Ryosuke Niwa <[email protected]>
+
Add the check for reentrancy to CustomElementRegistry
https://bugs.webkit.org/show_bug.cgi?id=161423
Modified: trunk/LayoutTests/fast/custom-elements/CustomElementRegistry-expected.txt (205262 => 205263)
--- trunk/LayoutTests/fast/custom-elements/CustomElementRegistry-expected.txt 2016-08-31 19:39:06 UTC (rev 205262)
+++ trunk/LayoutTests/fast/custom-elements/CustomElementRegistry-expected.txt 2016-08-31 19:53:44 UTC (rev 205263)
@@ -1,6 +1,7 @@
PASS CustomElementRegistry interface must have define as a method
PASS customElements.define must throw when the element interface is not a constructor
+PASS customElements.define must not throw the constructor is HTMLElement
PASS customElements.define must throw with an invalid name
PASS customElements.define must throw when there is already a custom element of the same name
PASS customElements.define must throw a NotSupportedError when there is already a custom element with the same class
Modified: trunk/LayoutTests/fast/custom-elements/CustomElementRegistry.html (205262 => 205263)
--- trunk/LayoutTests/fast/custom-elements/CustomElementRegistry.html 2016-08-31 19:39:06 UTC (rev 205262)
+++ trunk/LayoutTests/fast/custom-elements/CustomElementRegistry.html 2016-08-31 19:53:44 UTC (rev 205263)
@@ -29,6 +29,10 @@
}, 'customElements.define must throw when the element interface is not a constructor');
test(function () {
+ customElements.define('custom-html-element', HTMLElement);
+}, 'customElements.define must not throw the constructor is HTMLElement');
+
+test(function () {
class MyCustomElement extends HTMLElement {};
assert_throws({'name': 'SyntaxError'}, function () { customElements.define(null, MyCustomElement); },
Modified: trunk/LayoutTests/fast/custom-elements/HTMLElement-constructor-expected.txt (205262 => 205263)
--- trunk/LayoutTests/fast/custom-elements/HTMLElement-constructor-expected.txt 2016-08-31 19:39:06 UTC (rev 205262)
+++ trunk/LayoutTests/fast/custom-elements/HTMLElement-constructor-expected.txt 2016-08-31 19:53:44 UTC (rev 205263)
@@ -1,6 +1,7 @@
-PASS HTMLElement constructor must throw a TypeError when there is no derived class
-PASS HTMLElement constructor must throw TypeError when custom element is not well defined
+PASS HTMLElement constructor must throw a TypeError when NewTarget is equal to itself
+PASS HTMLElement constructor must throw a TypeError when NewTarget is equal to itself via a Proxy object
+PASS HTMLElement constructor must throw TypeError when it has not been defined by customElements.define
PASS HTMLElement constructor must infer the tag name from the element interface
PASS HTMLElement constructor must allow subclassing a custom element
PASS HTMLElement constructor must allow subclassing an user-defined subclass of HTMLElement
Modified: trunk/LayoutTests/fast/custom-elements/HTMLElement-constructor.html (205262 => 205263)
--- trunk/LayoutTests/fast/custom-elements/HTMLElement-constructor.html 2016-08-31 19:39:06 UTC (rev 205262)
+++ trunk/LayoutTests/fast/custom-elements/HTMLElement-constructor.html 2016-08-31 19:53:44 UTC (rev 205263)
@@ -4,6 +4,7 @@
<title>Custom Elements: HTMLElement must allow subclassing</title>
<meta name="author" title="Ryosuke Niwa" href=""
<meta name="assert" content="HTMLElement must allow subclassing">
+<link rel="help" href=""
<script src=""
<script src=""
<link rel='stylesheet' href=''>
@@ -13,16 +14,19 @@
<script>
test(function () {
- class SomeDefinedElement extends HTMLElement {};
- customElements.define('defined-element', SomeDefinedElement);
- assert_throws({'name': 'TypeError'}, function () { new HTMLElement('defined-element'); });
-}, 'HTMLElement constructor must throw a TypeError when there is no derived class');
+ customElements.define('html-custom-element', HTMLElement);
+ assert_throws({'name': 'TypeError'}, function () { new HTMLElement(); });
+}, 'HTMLElement constructor must throw a TypeError when NewTarget is equal to itself');
test(function () {
+ customElements.define('html-proxy-custom-element', new Proxy(HTMLElement, {}));
+ assert_throws({'name': 'TypeError'}, function () { new HTMLElement(); });
+}, 'HTMLElement constructor must throw a TypeError when NewTarget is equal to itself via a Proxy object');
+
+test(function () {
class SomeCustomElement extends HTMLElement {};
- assert_throws({'name': 'TypeError'}, function () { new SomeCustomElement; },
- 'Instantiating a custom element without calling customElements.define must throw TypeError');
-}, 'HTMLElement constructor must throw TypeError when custom element is not well defined');
+ assert_throws({'name': 'TypeError'}, function () { new SomeCustomElement; });
+}, 'HTMLElement constructor must throw TypeError when it has not been defined by customElements.define');
test(function () {
class CustomElementWithInferredTagName extends HTMLElement {};
Modified: trunk/Source/WebCore/ChangeLog (205262 => 205263)
--- trunk/Source/WebCore/ChangeLog 2016-08-31 19:39:06 UTC (rev 205262)
+++ trunk/Source/WebCore/ChangeLog 2016-08-31 19:53:44 UTC (rev 205263)
@@ -1,5 +1,25 @@
2016-08-31 Ryosuke Niwa <[email protected]>
+ HTML constructor must throw when newTarget is itself
+ https://bugs.webkit.org/show_bug.cgi?id=161430
+
+ Reviewed by Antti Koivisto.
+
+ Per https://github.com/w3c/webcomponents/issues/541, we must throw a TypeError when the HTMLElement constructor
+ is called with new.target set to itself (i.e. new HTMLElement after registering it with a custom element).
+
+ Note that we can't check this at the time of customElements.define because it could be a Proxy object.
+
+ Also see: https://html.spec.whatwg.org/#html-element-constructors
+
+ Tests: fast/custom-elements/CustomElementRegistry.html
+ fast/custom-elements/HTMLElement-constructor.html
+
+ * bindings/js/JSHTMLElementCustom.cpp:
+ (WebCore::constructJSHTMLElement): Throw a TypeError when NewTarget is HTMLElement constructor itself.
+
+2016-08-31 Ryosuke Niwa <[email protected]>
+
Rebaseline binding tests after r205257.
* bindings/scripts/test/JS/JSTestObj.cpp:
Modified: trunk/Source/WebCore/bindings/js/JSHTMLElementCustom.cpp (205262 => 205263)
--- trunk/Source/WebCore/bindings/js/JSHTMLElementCustom.cpp 2016-08-31 19:39:06 UTC (rev 205262)
+++ trunk/Source/WebCore/bindings/js/JSHTMLElementCustom.cpp 2016-08-31 19:53:44 UTC (rev 205263)
@@ -54,6 +54,12 @@
return throwConstructorScriptExecutionContextUnavailableError(exec, scope, "HTMLElement");
ASSERT(context->isDocument());
+ JSValue newTargetValue = exec.thisValue();
+ auto* globalObject = jsConstructor->globalObject();
+ JSValue htmlElementConstructorValue = JSHTMLElement::getConstructor(vm, globalObject);
+ if (newTargetValue == htmlElementConstructorValue)
+ return throwVMTypeError(&exec, scope, ASCIILiteral("new.target is not a valid custom element constructor"));
+
auto& document = downcast<Document>(*context);
auto* window = document.domWindow();
@@ -64,7 +70,6 @@
if (!registry)
return throwVMTypeError(&exec, scope, ASCIILiteral("new.target is not a valid custom element constructor"));
- JSValue newTargetValue = exec.thisValue();
JSObject* newTarget = newTargetValue.getObject();
auto* elementInterface = registry->findInterface(newTarget);
if (!elementInterface)
@@ -71,7 +76,6 @@
return throwVMTypeError(&exec, scope, ASCIILiteral("new.target does not define a custom element"));
if (!elementInterface->isUpgradingElement()) {
- auto* globalObject = jsConstructor->globalObject();
Structure* baseStructure = getDOMStructure<JSHTMLElement>(vm, *globalObject);
auto* newElementStructure = InternalFunction::createSubclassStructure(&exec, newTargetValue, baseStructure);
if (UNLIKELY(exec.hadException()))