WebKit Bugzilla
Attachment 346729 Details for
Bug 187319
: document.open and document.write must throw while the HTML parser is synchronously constructing a custom element
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch for landing
bug-187319-20180807140417.patch (text/plain), 32.14 KB, created by
Ryosuke Niwa
on 2018-08-07 14:04:18 PDT
(
hide
)
Description:
Patch for landing
Filename:
MIME Type:
Creator:
Ryosuke Niwa
Created:
2018-08-07 14:04:18 PDT
Size:
32.14 KB
patch
obsolete
>Subversion Revision: 234583 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 09da9fd238a829a70f989a4a1a1e41fb94d94f48..c22e18214bb66b3bd9d87859f7243483f316ca71 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,33 @@ >+2018-08-06 Ryosuke Niwa <rniwa@webkit.org> >+ >+ document.open and document.write must throw while the HTML parser is synchronously constructing a custom element >+ https://bugs.webkit.org/show_bug.cgi?id=187319 >+ <rdar://problem/42843012> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Make document.open, document.write, document.writeln, and document.close throw InvalidStateError during >+ a synchronous custom element construction as specified: >+ https://html.spec.whatwg.org/multipage/parsing.html#create-an-element-for-the-token >+ https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#throw-on-dynamic-markup-insertion-counter >+ >+ Tests: fast/custom-elements/throw-on-dynamic-markup-insertion-counter-construct.html >+ fast/custom-elements/throw-on-dynamic-markup-insertion-counter-reactions.html >+ >+ * WebCore.xcodeproj/project.pbxproj: >+ * dom/Document.cpp: >+ (WebCore::Document::openForBindings): Throw InvalidStateError when m_throwOnDynamicMarkupInsertionCount is non-zero. >+ (WebCore::Document::closeForBindings): Ditto. >+ (WebCore::Document::write): Ditto. >+ (WebCore::Document::writeln): Ditto. >+ * dom/Document.h: Re-ordered the related instance variables in the order they appear in the spec, and updated spec URLs. >+ * dom/ThrowOnDynamicMarkupInsertionCountIncrementer.h: Added. >+ (WebCore::ThrowOnDynamicMarkupInsertionCountIncrementer): Added. >+ (WebCore::ThrowOnDynamicMarkupInsertionCountIncrementer::ThrowOnDynamicMarkupInsertionCountIncrementer): >+ (WebCore::ThrowOnDynamicMarkupInsertionCountIncrementer::~ThrowOnDynamicMarkupInsertionCountIncrementer): >+ * html/parser/HTMLDocumentParser.cpp: >+ (WebCore::HTMLDocumentParser::runScriptsForPausedTreeBuilder): Instantiate ThrowOnDynamicMarkupInsertionCountIncrementer. >+ > 2018-08-05 Ryosuke Niwa <rniwa@webkit.org> > > HTML parser should execute custom element reactions for setting attributes immediately after creating a custom element >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index cee8d7ef7c336e25564e9a217cda002841999849..1994510339d270995d5167942f1f94a83c6fb1dd 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -10851,6 +10851,7 @@ > 9B32CDA813DF7FA900F34D13 /* RenderedPosition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderedPosition.cpp; sourceTree = "<group>"; }; > 9B417062125662B3006B28FC /* ApplyBlockElementCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplyBlockElementCommand.h; sourceTree = "<group>"; }; > 9B417063125662B3006B28FC /* ApplyBlockElementCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ApplyBlockElementCommand.cpp; sourceTree = "<group>"; }; >+ 9B4376EF2117E872009D03A0 /* ThrowOnDynamicMarkupInsertionCountIncrementer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThrowOnDynamicMarkupInsertionCountIncrementer.h; sourceTree = "<group>"; }; > 9B50B1DC17CD4C0F0087F63C /* FormNamedItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormNamedItem.h; sourceTree = "<group>"; }; > 9B532EA11BA928570038A827 /* SlotAssignment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SlotAssignment.cpp; sourceTree = "<group>"; }; > 9B532EA21BA928570038A827 /* SlotAssignment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlotAssignment.h; sourceTree = "<group>"; }; >@@ -26563,6 +26564,7 @@ > A77B419F12E675A90054343D /* TextEventInputType.h */, > E4D988B517BFEB210084FB88 /* TextNodeTraversal.cpp */, > E4D988B317BFD1F60084FB88 /* TextNodeTraversal.h */, >+ 9B4376EF2117E872009D03A0 /* ThrowOnDynamicMarkupInsertionCountIncrementer.h */, > 0F54DD051881D5F5003EEDBB /* Touch.h */, > 0F54DD061881D5F5003EEDBB /* TouchEvent.h */, > 0F54DD071881D5F5003EEDBB /* TouchList.h */, >diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp >index d0ebe6ff7f984e723772fe14f3c5144084fbe46b..5203257ab64762f995ee586c8580247f471b8a1a 100644 >--- a/Source/WebCore/dom/Document.cpp >+++ b/Source/WebCore/dom/Document.cpp >@@ -2609,7 +2609,7 @@ ExceptionOr<RefPtr<WindowProxy>> Document::openForBindings(DOMWindow& activeWind > // FIXME: Add support for the 'type' and 'replace' parameters. > ExceptionOr<Document&> Document::openForBindings(Document* responsibleDocument, const String&, const String&) > { >- if (!isHTMLDocument()) >+ if (!isHTMLDocument() || m_throwOnDynamicMarkupInsertionCount) > return Exception { InvalidStateError }; > > // FIXME: This should also throw if "document's throw-on-dynamic-markup-insertion counter is greater than 0". >@@ -2753,7 +2753,7 @@ ExceptionOr<void> Document::closeForBindings() > // FIXME: We should follow the specification more closely: > // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-close > >- if (!isHTMLDocument()) >+ if (!isHTMLDocument() || m_throwOnDynamicMarkupInsertionCount) > return Exception { InvalidStateError }; > > // FIXME: This should also throw if "document's throw-on-dynamic-markup-insertion counter is greater than 0". >@@ -2984,7 +2984,7 @@ void Document::write(Document* responsibleDocument, SegmentedString&& text) > > ExceptionOr<void> Document::write(Document* responsibleDocument, Vector<String>&& strings) > { >- if (!isHTMLDocument()) >+ if (!isHTMLDocument() || m_throwOnDynamicMarkupInsertionCount) > return Exception { InvalidStateError }; > > // FIXME: This should also throw if "document's throw-on-dynamic-markup-insertion counter is greater than 0". >@@ -3001,7 +3001,7 @@ ExceptionOr<void> Document::write(Document* responsibleDocument, Vector<String>& > > ExceptionOr<void> Document::writeln(Document* responsibleDocument, Vector<String>&& strings) > { >- if (!isHTMLDocument()) >+ if (!isHTMLDocument() || m_throwOnDynamicMarkupInsertionCount) > return Exception { InvalidStateError }; > > // FIXME: This should also throw if "document's throw-on-dynamic-markup-insertion counter is greater than 0". >diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h >index 83b0889c09984984fa268354a8f47145be7c282b..f0de01a42d2a58a7377dcd5eb98fe222e80daca6 100644 >--- a/Source/WebCore/dom/Document.h >+++ b/Source/WebCore/dom/Document.h >@@ -1480,8 +1480,9 @@ protected: > private: > friend class DocumentParserYieldToken; > friend class Node; >- friend class IgnoreDestructiveWriteCountIncrementer; >+ friend class ThrowOnDynamicMarkupInsertionCountIncrementer; > friend class IgnoreOpensDuringUnloadCountIncrementer; >+ friend class IgnoreDestructiveWriteCountIncrementer; > > bool shouldInheritContentSecurityPolicyFromOwner() const; > >@@ -1854,12 +1855,15 @@ private: > int m_loadEventDelayCount { 0 }; > unsigned m_lastStyleUpdateSizeForTesting { 0 }; > >- // https://html.spec.whatwg.org/multipage/webappapis.html#ignore-destructive-writes-counter >- unsigned m_ignoreDestructiveWriteCount { 0 }; >+ // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#throw-on-dynamic-markup-insertion-counter >+ unsigned m_throwOnDynamicMarkupInsertionCount { 0 }; > >- // https://html.spec.whatwg.org/multipage/webappapis.html#ignore-opens-during-unload-counter >+ // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#ignore-opens-during-unload-counter > unsigned m_ignoreOpensDuringUnloadCount { 0 }; > >+ // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#ignore-destructive-writes-counter >+ unsigned m_ignoreDestructiveWriteCount { 0 }; >+ > unsigned m_activeParserCount { 0 }; > unsigned m_styleRecalcCount { 0 }; > >diff --git a/Source/WebCore/dom/ThrowOnDynamicMarkupInsertionCountIncrementer.h b/Source/WebCore/dom/ThrowOnDynamicMarkupInsertionCountIncrementer.h >new file mode 100644 >index 0000000000000000000000000000000000000000..83e71fa371f1a6f30fb4a5faf85f8b774b8a1df8 >--- /dev/null >+++ b/Source/WebCore/dom/ThrowOnDynamicMarkupInsertionCountIncrementer.h >@@ -0,0 +1,51 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#include "Document.h" >+ >+namespace WebCore { >+ >+class ThrowOnDynamicMarkupInsertionCountIncrementer { >+ WTF_MAKE_NONCOPYABLE(ThrowOnDynamicMarkupInsertionCountIncrementer); >+public: >+ explicit ThrowOnDynamicMarkupInsertionCountIncrementer(Document& document) >+ : m_document(document) >+ { >+ ++document.m_throwOnDynamicMarkupInsertionCount; >+ } >+ >+ ~ThrowOnDynamicMarkupInsertionCountIncrementer() >+ { >+ ASSERT(m_document->m_throwOnDynamicMarkupInsertionCount); >+ --m_document->m_throwOnDynamicMarkupInsertionCount; >+ } >+ >+private: >+ Ref<Document> m_document; >+}; >+ >+} // namespace WebCore >diff --git a/Source/WebCore/html/parser/HTMLDocumentParser.cpp b/Source/WebCore/html/parser/HTMLDocumentParser.cpp >index 3f3e7993ed9c735381c314e897a7b859e1e634b9..ad2ab6cdb974b270d53e66466e945419c7007244 100644 >--- a/Source/WebCore/html/parser/HTMLDocumentParser.cpp >+++ b/Source/WebCore/html/parser/HTMLDocumentParser.cpp >@@ -41,6 +41,7 @@ > #include "LinkLoader.h" > #include "NavigationScheduler.h" > #include "ScriptElement.h" >+#include "ThrowOnDynamicMarkupInsertionCountIncrementer.h" > > namespace WebCore { > >@@ -210,6 +211,8 @@ void HTMLDocumentParser::runScriptsForPausedTreeBuilder() > > // https://html.spec.whatwg.org/#create-an-element-for-the-token > { >+ // Prevent document.open/write during reactions by allocating the incrementer before the reactions stack. >+ ThrowOnDynamicMarkupInsertionCountIncrementer incrementer(*document()); > CustomElementReactionStack reactionStack(document()->execState()); > auto& elementInterface = constructionData->elementInterface.get(); > auto newElement = elementInterface.constructElementWithFallback(*document(), constructionData->name); >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 981ca45e34127ae6ce1eb8b79996a64b25f4a0a0..408f2bc5d449650ea50f37c9df4a9483b555a152 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,20 @@ >+2018-08-06 Ryosuke Niwa <rniwa@webkit.org> >+ >+ document.open and document.write must throw while the HTML parser is synchronously constructing a custom element >+ https://bugs.webkit.org/show_bug.cgi?id=187319 >+ <rdar://problem/42843012> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Added W3C style testharness.js tests. The WPT test added by https://github.com/web-platform-tests/wpt/pull/12037 >+ doesn't test nearly as many edge cases. >+ >+ * fast/custom-elements/resources/navigation-destination.html: Added. >+ * fast/custom-elements/throw-on-dynamic-markup-insertion-counter-construct-expected.txt: Added. >+ * fast/custom-elements/throw-on-dynamic-markup-insertion-counter-construct.html: Added. >+ * fast/custom-elements/throw-on-dynamic-markup-insertion-counter-reactions-expected.txt: Added. >+ * fast/custom-elements/throw-on-dynamic-markup-insertion-counter-reactions.html: Added. >+ > 2018-08-05 Philippe Normand <pnormand@igalia.com> > > [MediaCapabilities] Platform integration >diff --git a/LayoutTests/fast/custom-elements/resources/navigation-destination.html b/LayoutTests/fast/custom-elements/resources/navigation-destination.html >new file mode 100644 >index 0000000000000000000000000000000000000000..ede8d2c6eb13ea0d8b633780160811559e283950 >--- /dev/null >+++ b/LayoutTests/fast/custom-elements/resources/navigation-destination.html >@@ -0,0 +1,9 @@ >+<!DOCTYPE html> >+<html> >+<body> >+<p>Navigated!</p> >+<script> >+parent.postMessage('didNavigate', '*'); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/fast/custom-elements/throw-on-dynamic-markup-insertion-counter-construct-expected.txt b/LayoutTests/fast/custom-elements/throw-on-dynamic-markup-insertion-counter-construct-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..d976fe770479edebc867449bfe18960a7c31839a >--- /dev/null >+++ b/LayoutTests/fast/custom-elements/throw-on-dynamic-markup-insertion-counter-construct-expected.txt >@@ -0,0 +1,13 @@ >+ >+PASS document.open() must throw an InvalidStateError when synchronously constructing a custom element >+PASS document.open("text/html") must throw an InvalidStateError when synchronously constructing a custom element >+PASS document.open(URL) must NOT throw an InvalidStateError when synchronously constructing a custom element >+PASS document.close() must throw an InvalidStateError when synchronously constructing a custom element >+PASS document.write must throw an InvalidStateError when synchronously constructing a custom element >+PASS document.writeln must throw an InvalidStateError when synchronously constructing a custom element >+PASS document.open() of another document must not throw an InvalidStateError when synchronously constructing a custom element >+PASS document.open("text/html") of another document must not throw an InvalidStateError when synchronously constructing a custom element >+PASS document.close() of another document must not throw an InvalidStateError when synchronously constructing a custom element >+PASS document.write of another document must not throw an InvalidStateError when synchronously constructing a custom element >+PASS document.writeln of another document must not throw an InvalidStateError when synchronously constructing a custom element >+ >diff --git a/LayoutTests/fast/custom-elements/throw-on-dynamic-markup-insertion-counter-construct.html b/LayoutTests/fast/custom-elements/throw-on-dynamic-markup-insertion-counter-construct.html >new file mode 100644 >index 0000000000000000000000000000000000000000..aa4c7b0dbfe6d13e4f03449862c174147776033c >--- /dev/null >+++ b/LayoutTests/fast/custom-elements/throw-on-dynamic-markup-insertion-counter-construct.html >@@ -0,0 +1,117 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<title>Custom Elements: create an element for a token must increment and decrement document's throw-on-dynamic-markup-insertion counter</title> >+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> >+<meta name="assert" content="Invoking document.open, document.write, document.writeln, and document.write must throw an exception when the HTML parser is creating a custom element for a token"> >+<meta name="help" content="https://html.spec.whatwg.org/multipage/parsing.html#create-an-element-for-the-token"> >+<meta name="help" content="https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#throw-on-dynamic-markup-insertion-counter"> >+<script src="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../../imported/w3c/web-platform-tests/custom-elements/resources/custom-elements-helpers.js"></script> >+</head> >+<body> >+<div id="log"></div> >+<script> >+ >+async function construct_custom_element_in_parser(test, call_function) >+{ >+ const window = await create_window_in_test(test); >+ const document = window.document; >+ >+ document.open(); >+ >+ let executed = false; >+ let exception = null; >+ class CustomElement extends window.HTMLElement { >+ constructor() { >+ super(); >+ try { >+ call_function(document, window); >+ } catch (error) { >+ exception = error; >+ } >+ executed = true; >+ } >+ } >+ window.customElements.define('some-element', CustomElement); >+ >+ document.write('<!DOCTYPE html><html><body><some-element></some-element></body></html>'); >+ document.close(); >+ >+ assert_true(executed, 'Must synchronously instantiate a custom element'); >+ return {window, document, exception}; >+} >+ >+promise_test(async function () { >+ const result = await construct_custom_element_in_parser(this, (document) => document.open()); >+ assert_throws({name: 'InvalidStateError'}, () => { throw result.exception; }, 'Must throw an InvalidStateError'); >+}, 'document.open() must throw an InvalidStateError when synchronously constructing a custom element'); >+ >+promise_test(async function () { >+ const result = await construct_custom_element_in_parser(this, (document) => document.open('text/html')); >+ assert_throws({name: 'InvalidStateError'}, () => { throw result.exception; }, 'Must throw an InvalidStateError'); >+}, 'document.open("text/html") must throw an InvalidStateError when synchronously constructing a custom element'); >+ >+// https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-document-open-window >+promise_test(async function () { >+ let load_promise = new Promise((resolve) => window.onmessage = (event) => resolve(event.data)); >+ const result = await construct_custom_element_in_parser(this, (document, window) => document.open('resources/navigation-destination.html', '_self', '')); >+ assert_equals(result.exception, null); >+ assert_equals(await load_promise, 'didNavigate'); >+}, 'document.open(URL) must NOT throw an InvalidStateError when synchronously constructing a custom element'); >+ >+promise_test(async function () { >+ const result = await construct_custom_element_in_parser(this, (document) => document.close()); >+ assert_throws({name: 'InvalidStateError'}, () => { throw result.exception; }, 'Must throw an InvalidStateError'); >+}, 'document.close() must throw an InvalidStateError when synchronously constructing a custom element'); >+ >+promise_test(async function () { >+ const result = await construct_custom_element_in_parser(this, (document) => document.write('<b>some text</b>')); >+ assert_throws({name: 'InvalidStateError'}, () => { throw result.exception; }, 'Must throw an InvalidStateError'); >+ assert_equals(result.document.querySelector('b'), null, 'Must not insert new content'); >+ assert_false(result.document.documentElement.innerHTML.includes('some text'), 'Must not insert new content'); >+}, 'document.write must throw an InvalidStateError when synchronously constructing a custom element'); >+ >+promise_test(async function () { >+ const result = await construct_custom_element_in_parser(this, (document) => document.writeln('<b>some text</b>')); >+ assert_throws({name: 'InvalidStateError'}, () => { throw result.exception; }, 'Must throw an InvalidStateError'); >+ assert_equals(result.document.querySelector('b'), null, 'Must not insert new content'); >+ assert_false(result.document.documentElement.innerHTML.includes('some text'), 'Must not insert new content'); >+}, 'document.writeln must throw an InvalidStateError when synchronously constructing a custom element'); >+ >+promise_test(async function () { >+ const another_window = await create_window_in_test(this); >+ const result = await construct_custom_element_in_parser(this, (document) => another_window.document.open()); >+ assert_equals(result.exception, null); >+}, 'document.open() of another document must not throw an InvalidStateError when synchronously constructing a custom element'); >+ >+promise_test(async function () { >+ const another_window = await create_window_in_test(this); >+ const result = await construct_custom_element_in_parser(this, (document) => another_window.document.open('text/html')); >+ assert_equals(result.exception, null); >+}, 'document.open("text/html") of another document must not throw an InvalidStateError when synchronously constructing a custom element'); >+ >+promise_test(async function () { >+ const another_window = await create_window_in_test(this); >+ const result = await construct_custom_element_in_parser(this, (document) => another_window.document.close()); >+ assert_equals(result.exception, null); >+}, 'document.close() of another document must not throw an InvalidStateError when synchronously constructing a custom element'); >+ >+promise_test(async function () { >+ const another_window = await create_window_in_test(this); >+ const result = await construct_custom_element_in_parser(this, (document) => another_window.document.write('<b>some text</b>')); >+ assert_equals(result.exception, null); >+ assert_equals(another_window.document.querySelector('b').outerHTML, '<b>some text</b>'); >+}, 'document.write of another document must not throw an InvalidStateError when synchronously constructing a custom element'); >+ >+promise_test(async function () { >+ const another_window = await create_window_in_test(this); >+ const result = await construct_custom_element_in_parser(this, (document) => another_window.document.writeln('<b>some text</b>')); >+ assert_equals(result.exception, null); >+ assert_equals(another_window.document.querySelector('b').outerHTML, '<b>some text</b>'); >+}, 'document.writeln of another document must not throw an InvalidStateError when synchronously constructing a custom element'); >+ >+</script> >+</body> >+</html> >diff --git a/LayoutTests/fast/custom-elements/throw-on-dynamic-markup-insertion-counter-reactions-expected.txt b/LayoutTests/fast/custom-elements/throw-on-dynamic-markup-insertion-counter-reactions-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..e19ed11945bd69013c74aa5b09bfe2fdb2634cf8 >--- /dev/null >+++ b/LayoutTests/fast/custom-elements/throw-on-dynamic-markup-insertion-counter-reactions-expected.txt >@@ -0,0 +1,13 @@ >+ >+PASS document.open() must throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element >+PASS document.open("text/html") must throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element >+PASS document.open(URL) must NOT throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element >+PASS document.close() must throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element >+PASS document.write must throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element >+PASS document.writeln must throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element >+PASS document.open() of another document must not throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element >+PASS document.open("text/html") of another document must not throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element >+PASS document.close() of another document must not throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element >+PASS document.write of another document must not throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element >+PASS document.writeln of another document must not throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element >+ >diff --git a/LayoutTests/fast/custom-elements/throw-on-dynamic-markup-insertion-counter-reactions.html b/LayoutTests/fast/custom-elements/throw-on-dynamic-markup-insertion-counter-reactions.html >new file mode 100644 >index 0000000000000000000000000000000000000000..c6cd7c60e70534b5aa4997b3f6ece557a4bcc818 >--- /dev/null >+++ b/LayoutTests/fast/custom-elements/throw-on-dynamic-markup-insertion-counter-reactions.html >@@ -0,0 +1,117 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<title>Custom Elements: create an element for a token must increment and decrement document's throw-on-dynamic-markup-insertion counter</title> >+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> >+<meta name="assert" content="Invoking document.open, document.write, document.writeln, and document.write must throw an exception when the HTML parser is creating a custom element for a token"> >+<meta name="help" content="https://html.spec.whatwg.org/multipage/parsing.html#create-an-element-for-the-token"> >+<meta name="help" content="https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#throw-on-dynamic-markup-insertion-counter"> >+<script src="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../../imported/w3c/web-platform-tests/custom-elements/resources/custom-elements-helpers.js"></script> >+</head> >+<body> >+<div id="log"></div> >+<script> >+ >+async function custom_element_reactions_in_parser(test, call_function) >+{ >+ const window = await create_window_in_test(test); >+ const document = window.document; >+ >+ document.open(); >+ >+ let executed = false; >+ let exception = null; >+ class CustomElement extends window.HTMLElement { >+ attributeChangedCallback(name, oldValue, newValue) { >+ try { >+ call_function(document, window); >+ } catch (error) { >+ exception = error; >+ } >+ executed = true; >+ } >+ } >+ CustomElement.observedAttributes = ['title']; >+ window.customElements.define('some-element', CustomElement); >+ >+ document.write('<!DOCTYPE html><html><body><some-element title="some title"></some-element></body></html>'); >+ document.close(); >+ >+ assert_true(executed, 'Must immediately process custom element reactions for setting attributes'); >+ return {frameElement, window, document, exception}; >+} >+ >+promise_test(async function () { >+ const result = await custom_element_reactions_in_parser(this, (document) => document.open()); >+ assert_throws({name: 'InvalidStateError'}, () => { throw result.exception; }, 'Must throw an InvalidStateError'); >+}, 'document.open() must throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element'); >+ >+promise_test(async function () { >+ const result = await custom_element_reactions_in_parser(this, (document) => document.open('text/html')); >+ assert_throws({name: 'InvalidStateError'}, () => { throw result.exception; }, 'Must throw an InvalidStateError'); >+}, 'document.open("text/html") must throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element'); >+ >+// https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-document-open-window >+promise_test(async function () { >+ let load_promise = new Promise((resolve) => window.onmessage = (event) => resolve(event.data)); >+ const result = await custom_element_reactions_in_parser(this, (document, window) => document.open('resources/navigation-destination.html', '_self', '')); >+ assert_equals(result.exception, null); >+ assert_equals(await load_promise, 'didNavigate'); >+}, 'document.open(URL) must NOT throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element'); >+ >+promise_test(async function () { >+ const result = await custom_element_reactions_in_parser(this, (document) => document.close()); >+ assert_throws({name: 'InvalidStateError'}, () => { throw result.exception; }, 'Must throw an InvalidStateError'); >+}, 'document.close() must throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element'); >+ >+promise_test(async function () { >+ const result = await custom_element_reactions_in_parser(this, (document) => document.write('<b>some text</b>')); >+ assert_throws({name: 'InvalidStateError'}, () => { throw result.exception; }, 'Must throw an InvalidStateError'); >+ assert_equals(result.document.querySelector('b'), null, 'Must not insert new content'); >+ assert_false(result.document.documentElement.innerHTML.includes('some text'), 'Must not insert new content'); >+}, 'document.write must throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element'); >+ >+promise_test(async function () { >+ const result = await custom_element_reactions_in_parser(this, (document) => document.writeln('<b>some text</b>')); >+ assert_throws({name: 'InvalidStateError'}, () => { throw result.exception; }, 'Must throw an InvalidStateError'); >+ assert_equals(result.document.querySelector('b'), null, 'Must not insert new content'); >+ assert_false(result.document.documentElement.innerHTML.includes('some text'), 'Must not insert new content'); >+}, 'document.writeln must throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element'); >+ >+promise_test(async function () { >+ const another_window = await create_window_in_test(this); >+ const result = await custom_element_reactions_in_parser(this, (document) => another_window.document.open()); >+ assert_equals(result.exception, null); >+}, 'document.open() of another document must not throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element'); >+ >+promise_test(async function () { >+ const another_window = await create_window_in_test(this); >+ const result = await custom_element_reactions_in_parser(this, (document) => another_window.document.open('text/html')); >+ assert_equals(result.exception, null); >+}, 'document.open("text/html") of another document must not throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element'); >+ >+promise_test(async function () { >+ const another_window = await create_window_in_test(this); >+ const result = await custom_element_reactions_in_parser(this, (document) => another_window.document.close()); >+ assert_equals(result.exception, null); >+}, 'document.close() of another document must not throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element'); >+ >+promise_test(async function () { >+ const another_window = await create_window_in_test(this); >+ const result = await custom_element_reactions_in_parser(this, (document) => another_window.document.write('<b>some text</b>')); >+ assert_equals(result.exception, null); >+ assert_equals(another_window.document.querySelector('b').outerHTML, '<b>some text</b>'); >+}, 'document.write of another document must not throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element'); >+ >+promise_test(async function () { >+ const another_window = await create_window_in_test(this); >+ const result = await custom_element_reactions_in_parser(this, (document) => another_window.document.writeln('<b>some text</b>')); >+ assert_equals(result.exception, null); >+ assert_equals(another_window.document.querySelector('b').outerHTML, '<b>some text</b>'); >+}, 'document.writeln of another document must not throw an InvalidStateError when processing custom element reactions for a synchronous constructed custom element'); >+ >+</script> >+</body> >+</html>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 187319
:
346686
|
346687
|
346729
|
346735